package Player;


import gdrObject.*;

import java.awt.Point;
import java.io.Serializable;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import javax.swing.Icon;
import javax.swing.ImageIcon;

import mission.Mission;
import mission.MissionStep;

import concept.Attributes;
import concept.AttributesType;


public class PG implements Serializable{
	
	public PG(String name, Race race, Faction belongingFaction){
        this.race = race;
        this.name = name;
        this.level = 1;
        attributes = new Attributes(race.getBaseIntelligence(), 
        		race.getBaseStrength(), 
        		race.getBaseAgility(), 
        		race.getBaseDetermination());
        expForLevel = 100 - attributes.getDetermination()*10; //FIXME
        maxLife = attributes.getStrength()*10 + 15;
        maxMana = attributes.getIntelligence()*10 + 5;

        this.exp = 0;
        this.belongingFaction = belongingFaction;
        this.money = 0;
        this.life = maxLife;
        this.mana = maxMana;
        backPack = new HashMap<String, GdrObject>();
        equippedWeapon = null;
        equippedArmor = null;
        unspentAttributePoints = 0;
        avatarBox = null;
        avatarNum = 0;
        story = null;
    }

    public PG(String name, Race race, int life, int mana, int level, int experience, Faction belongingFaction, int money, int unspentAttributesPoints, String history) throws Exception{
        this.race = race;
        this.name = name;
        if(level<=0 || experience<0 || money<0 || life<0 || mana<0) throw new Exception("negative value for variables");
        this.level = level;
        attributes = new Attributes(race.getBaseIntelligence(), 
        		race.getBaseStrength(), 
        		race.getBaseAgility(), 
        		race.getBaseDetermination());

        expForLevel = this.level*100 - attributes.getDetermination()*10;
        if(expForLevel<this.level*50)
        	expForLevel = this.level*50;
        maxLife = attributes.getStrength()*10 + this.level*5 + 10;
        maxMana = attributes.getIntelligence()*10 + this.level*5;

        if(experience>=expForLevel) throw new Exception("experience over the limit for next level");
        this.exp = experience;
        this.belongingFaction = belongingFaction;
        this.money = money;
        if(life>maxLife)
            this.life = maxLife;
        else
            this.life = life;
        if(mana>maxMana)
            this.mana = maxMana;
        else
            this.mana = mana;
        backPack = new HashMap<String, GdrObject>();
        equippedWeapon = null;
        equippedArmor = null;
        this.unspentAttributePoints = unspentAttributesPoints;
        avatarBox = null;
        avatarNum = 0;
        this.story = history;
    }

    public void addGdrObject(GdrObject obj){
        backPack.put(obj.getName(), obj);
    }

    public void addIntelligence(int intelligence){
        attributes.setIntelligence(attributes.getIntelligence() + intelligence);
    }

    public void addStrength(int strength){
    	attributes.setStrength(attributes.getStrength() + strength);
    }

    public void addAgility(int agility){
    	attributes.setAgility(attributes.getAgility() + agility);
    }

    public void addDetermination(int determination){
    	attributes.setDetermination(attributes.getDetermination() + determination);
    }

    public void spentAnAttributePoint(AttributesType attribute){
        this.unspentAttributePoints --;
        attributes.setAttribute(attribute, attributes.getAttribute(attribute) + 1);
    }

    public Race getRace(){
        return race;
    }

    public String getName(){
        return name;
    }

    public int getLevel(){
        return level;
    }

    public int getExperience(){
        return exp;
    }

    public int getExpForLevel(){
        return expForLevel;
    }

    public Faction getBelongingFaction(){
        return belongingFaction;
    }

    public int getMoney(){
        return money;
    }

    public int getLife(){
        return life;
    }

    public int getMana(){
        return mana;
    }

    public int getMaxLife(){
        return maxLife;
    }

    public int getMaxMana(){
        return maxMana;
    }

    public int getIntelligence(){
        return attributes.getIntelligence();
    }

    public int getStrength(){
        return attributes.getStrength();
    }

    public int getAgility(){
        return attributes.getAgility();
    }

    public int getDetermination(){
        return attributes.getDetermination();
    }
    
    public Attributes getAttributes() {
		return attributes;
	}

    public int getUnspentAttributePoints(){
        return unspentAttributePoints;
    }

    public GdrObject getObject(String objectName){
        return backPack.get(objectName);
    }

    public Collection<GdrObject> getBackPack(){
        return backPack.values();
    }

    public Weapon getEquippedWeapon(){
        return  equippedWeapon;
    }

    public Armor getEquippedArmor(){
        return equippedArmor;
    }

    public int getAvatarNum(){
        return avatarNum;
    }
    
    public String getAvatarBox(){
        return avatarBox;
    }

    public String getHistory(){
        return story;
    }

    public boolean removeObject(String objectName){
        if(backPack.containsKey(objectName)){
            backPack.remove(objectName);
            return true;
        }
        return false;
    }

    public void setAvatarBox(String avatarBox){
        this.avatarBox= avatarBox;
    }

    public void setAvatarNum(int avatarNum){
        this.avatarNum = avatarNum;
    }

    public void setHistory(String history){
        story = history;
    }

    public void setIntelligence(int intelligence) throws Exception{
        if(intelligence<0) throw new Exception("negative value for variables");
        attributes.setIntelligence(intelligence);
    }

    public void setStrength(int strength) throws Exception{
        if(strength<0) throw new Exception("negative value for variables");
        attributes.setStrength(strength);
    }

    public void setAgility(int agility) throws Exception{
        if(agility<0) throw new Exception("negative value for variables");
        attributes.setAgility(agility);
    }

    public void setDetermination(int determination) throws Exception{
        if(determination<0) throw new Exception("negative value for variables");
        attributes.setDetermination(determination);
    }

    public void setMoney(int money) throws Exception{
        if(money<0) throw new Exception("negative value for variables");
        this.money = money;
    }

    public void setLife(int life) throws Exception{
        if(life<0) throw new Exception("negative value for variables");
        if(life<maxLife)
            this.life = life;
        else
            this.life = maxLife;
    }

    public void setMana(int mana) throws Exception{
        if(mana<0) throw new Exception("negative value for variables");
        if(mana<maxMana)
            this.mana = mana;
        else
            this.mana = maxMana;
    }

    public void setUnspentAttributePoints(int unspentAttributesPoints){
        this.unspentAttributePoints = unspentAttributesPoints;
    }    

    public void upgradeLevel(){
        level++;
        updateVariablesDependingOnAttributes();
        exp = 0;
        unspentAttributePoints += 3;
    }

    public void addExperience(int valueToAdd) throws Exception{
        if(valueToAdd<0) throw new Exception("negative value for variables");
        int resultExp = exp + valueToAdd;
        if(resultExp>=expForLevel){
            int expToAdd = resultExp - expForLevel;
            this.upgradeLevel();
            this.addExperience(expToAdd);
        }
        else
            exp = resultExp;
    }

    public void updateVariablesDependingOnAttributes(){
        expForLevel = this.level*100 - attributes.getDetermination()*10;
        maxLife = attributes.getStrength()*10 + this.level*5 + 10;
        maxMana = attributes.getIntelligence()*10 + this.level*5;
    }
    
    public void packAwayEquippedWeapon(){
        Weapon w = this.getEquippedWeapon();
        if(w != null){
            equippedWeapon = null;
            this.addGdrObject(w);
        }
    }

    public void packAwayEquippedArmor(){
        Armor a = this.getEquippedArmor();
        if(a != null){
            equippedArmor = null;
            this.addGdrObject(a);
        }
    }

    public boolean canEquip(String equippmentName){
        if(backPack.containsKey(equippmentName)){
            GdrObject obj = backPack.get(equippmentName);
            if(obj instanceof Equippment){
                Equippment e = (Equippment) obj;
                if(e.getRequiredIntelligence()<=attributes.getIntelligence() && 
                		e.getRequiredStrength()<=attributes.getStrength() && 
                		e.getRequiredAgility()<=attributes.getAgility() && 
                		e.getRequiredDetermination()<=attributes.getDetermination()){
                	return true;
                }
            }
        }
        return false;
    }

    public void equipWeapon(String weaponName) throws Exception{
		if(backPack.containsKey(weaponName)){
		    GdrObject obj = backPack.get(weaponName);
		    if(obj instanceof Weapon){
		        Weapon w = (Weapon) obj;
		        if(w.getRequiredIntelligence()<=attributes.getIntelligence() && 
                		w.getRequiredStrength()<=attributes.getStrength() && 
                		w.getRequiredAgility()<=attributes.getAgility() && 
                		w.getRequiredDetermination()<=attributes.getDetermination()){
		        	this.packAwayEquippedWeapon();
		            equippedWeapon = w;
		        }
		        else
		            throw new Exception("requirements too high");
		    }
		    else
		        throw new Exception("it isn't a weapon");
		}
		else
		    throw new Exception("you don't have this weapon");
    }

    public void equipArmor(String armorName) throws Exception{
        if(backPack.containsKey(armorName)){
            GdrObject obj = backPack.get(armorName);
            if(obj instanceof Armor){
                Armor a = (Armor) obj;
                if(a.getRequiredIntelligence()<=attributes.getIntelligence() && 
                		a.getRequiredStrength()<=attributes.getStrength() && 
                		a.getRequiredAgility()<=attributes.getAgility() && 
                		a.getRequiredDetermination()<=attributes.getDetermination()){
                    this.packAwayEquippedArmor();
                    equippedArmor = a;
                }
                else
                    throw new Exception("requirements too high");
            }
            else
                throw new Exception("it isn't an armor");
        }
        else
            throw new Exception("you don't have this armor");
    }

    private String  name, story;
    private Race race;
    private int level, exp, expForLevel, money, life, maxLife, mana, maxMana, unspentAttributePoints;
    private Faction belongingFaction;
    private Attributes attributes;
    private HashMap<String, GdrObject> backPack;
    private Weapon equippedWeapon;
    private Armor equippedArmor;
    private String avatarBox;
    private int avatarNum;
    private static final long serialVersionUID = 2593186739693173586L;
}
